package main

import (
	"context"
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/xkgo/lcs/binary"
	"github.com/xkgo/lcs/server"
)

func main() {
	// 定义命令行参数
	host := flag.String("host", "localhost", "服务器主机名或IP")
	httpPort := flag.Int("http-port", 8083, "HTTP服务器端口号")
	rpcPort := flag.Int("rpc-port", 9083, "RPC服务器端口号")
	serverID := flag.String("server-id", "server1", "服务器ID")
	validatorURL := flag.String("validator-url", "http://localhost:8082/validate", "验证服务器URL")
	flag.Parse()

	// 构建服务器地址
	rpcAddr := fmt.Sprintf("%s:%d", *host, *rpcPort)

	// 创建服务器选项
	opts := server.DefaultServerOptions()
	opts.ServerID = *serverID
	opts.ServerAddr = rpcAddr
	
	// 启用token验证
	opts.EnableTokenValidation = true
	
	// 创建一个HTTP token验证器
	tokenValidator := server.NewHTTPTokenValidator()
	
	// 注册应用验证URL
	tokenValidator.RegisterURL("app1", *validatorURL)
	tokenValidator.RegisterURL("app2", *validatorURL)
	
	// 设置验证器
	opts.TokenValidator = tokenValidator

	// 创建长连接服务器
	wsServer := server.NewServer(opts)

	// 创建HTTP服务器
	httpServer := &http.Server{
		Addr: fmt.Sprintf("%s:%d", *host, *httpPort),
		Handler: corsMiddleware(http.DefaultServeMux),
	}

	// 设置WebSocket处理路由
	http.Handle("/ws", wsServer)

	// 添加静态文件服务，用于提供HTML客户端
	http.HandleFunc("/client", func(w http.ResponseWriter, r *http.Request) {
		http.ServeFile(w, r, "../../client_auth.html")
	})

	// 添加二进制客户端路由
	http.HandleFunc("/client/binary", func(w http.ResponseWriter, r *http.Request) {
		http.ServeFile(w, r, "../../client_binary_auth.html")
	})

	// 设置一个HTTP处理程序，用于发送广播消息
	http.HandleFunc("/broadcast", func(w http.ResponseWriter, r *http.Request) {
		if r.Method != http.MethodPost {
			http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
			return
		}

		topic := r.URL.Query().Get("topic")
		if topic == "" {
			http.Error(w, "Missing topic parameter", http.StatusBadRequest)
			return
		}

		// 限制请求体大小
		r.Body = http.MaxBytesReader(w, r.Body, 1024*1024)

		// 检查是否要使用二进制格式
		useBinary := r.URL.Query().Get("binary") == "true"

		if useBinary {
			// 使用二进制格式
			var msgData struct {
				Type    string `json:"type"`
				Content string `json:"content,omitempty"`
			}

			if err := json.NewDecoder(r.Body).Decode(&msgData); err != nil {
				http.Error(w, "Invalid message format", http.StatusBadRequest)
				return
			}

			// 创建二进制消息
			var binMsg *binary.Message
			if msgData.Type == "text" {
				binMsg = binary.NewTextMessage(msgData.Content)
			} else {
				http.Error(w, "Unsupported message type for binary format", http.StatusBadRequest)
				return
			}

			// 发布二进制消息到指定主题
			if err := wsServer.PublishBinary(topic, binMsg); err != nil {
				http.Error(w, "Failed to publish binary message: "+err.Error(), http.StatusInternalServerError)
				return
			}

			log.Printf("Published binary message to topic: %s", topic)
		} else {
			// 兼容旧版本，使用JSON格式
			var msg server.Message
			if err := json.NewDecoder(r.Body).Decode(&msg); err != nil {
				http.Error(w, "Invalid message format", http.StatusBadRequest)
				return
			}

			// 将消息转换为JSON
			msgBytes, err := json.Marshal(msg)
			if err != nil {
				http.Error(w, "Failed to marshal message", http.StatusInternalServerError)
				return
			}

			// 发布消息到指定主题
			wsServer.Publish(topic, msgBytes)
			log.Printf("Published JSON message to topic: %s", topic)
		}

		w.WriteHeader(http.StatusOK)
		w.Write([]byte("Message broadcasted"))
	})

	// 设置一个HTTP处理程序，用于发送单播消息
	http.HandleFunc("/send", func(w http.ResponseWriter, r *http.Request) {
		if r.Method != http.MethodPost {
			http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
			return
		}

		uid := r.URL.Query().Get("uid")
		if uid == "" {
			http.Error(w, "Missing uid parameter", http.StatusBadRequest)
			return
		}

		// 限制请求体大小
		r.Body = http.MaxBytesReader(w, r.Body, 1024*1024)

		// 检查是否要使用二进制格式
		useBinary := r.URL.Query().Get("binary") == "true"

		if useBinary {
			// 使用二进制格式
			var msgData struct {
				Type    string `json:"type"`
				Content string `json:"content,omitempty"`
			}

			if err := json.NewDecoder(r.Body).Decode(&msgData); err != nil {
				http.Error(w, "Invalid message format", http.StatusBadRequest)
				return
			}

			// 创建二进制消息
			var binMsg *binary.Message
			if msgData.Type == "text" {
				binMsg = binary.NewTextMessage(msgData.Content)
			} else {
				http.Error(w, "Unsupported message type for binary format", http.StatusBadRequest)
				return
			}

			// 发送二进制消息到指定客户端
			if err := wsServer.SendBinaryToClient(uid, binMsg); err != nil {
				http.Error(w, "Failed to send binary message: "+err.Error(), http.StatusInternalServerError)
				return
			}

			log.Printf("Sent binary message to client: %s", uid)
		} else {
			// 兼容旧版本，使用JSON格式
			var msg server.Message
			if err := json.NewDecoder(r.Body).Decode(&msg); err != nil {
				http.Error(w, "Invalid message format", http.StatusBadRequest)
				return
			}

			// 将消息转换为JSON
			msgBytes, err := json.Marshal(msg)
			if err != nil {
				http.Error(w, "Failed to marshal message", http.StatusInternalServerError)
				return
			}

			// 发送消息到指定客户端
			if err := wsServer.SendToClient(uid, msgBytes); err != nil {
				http.Error(w, "Failed to send message: "+err.Error(), http.StatusInternalServerError)
				return
			}

			log.Printf("Sent JSON message to client: %s", uid)
		}

		w.WriteHeader(http.StatusOK)
		w.Write([]byte("Message sent"))
	})

	// 设置一个HTTP处理程序，用于获取客户端连接信息
	http.HandleFunc("/clients", func(w http.ResponseWriter, r *http.Request) {
		if r.Method != http.MethodGet {
			http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
			return
		}

		// 获取客户端数量
		count := wsServer.GetClientCount()

		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		json.NewEncoder(w).Encode(map[string]interface{}{
			"count": count,
		})
	})

	// 捕获系统信号，优雅关闭
	stop := make(chan os.Signal, 1)
	signal.Notify(stop, os.Interrupt, syscall.SIGTERM)

	// 启动HTTP服务器
	go func() {
		log.Printf("Starting WebSocket server (ID: %s) with HTTP token validation", *serverID)
		log.Printf("HTTP server listening on http://%s:%d", *host, *httpPort)
		log.Printf("RPC server listening on %s", rpcAddr)
		log.Printf("Using validator URL: %s", *validatorURL)
		if err := httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			log.Fatalf("Error starting server: %v", err)
		}
	}()

	// 启动一个goroutine定期发送广播消息（模拟）
	go func() {
		ticker := time.NewTicker(10 * time.Second)
		defer ticker.Stop()

		for {
			select {
			case <-ticker.C:
				// 随机决定是否使用二进制格式
				useBinary := time.Now().Unix()%2 == 0 // 每隔一次切换一次

				if useBinary {
					// 使用二进制格式发送消息
					binMsg := binary.NewTextMessage("Server binary broadcast message: " + time.Now().Format(time.RFC3339))

					// 发布二进制消息到news主题
					if err := wsServer.PublishBinary("news", binMsg); err != nil {
						log.Printf("Failed to publish binary broadcast message: %v", err)
						continue
					}

					log.Println("Binary broadcast message sent to topic: news")
				} else {
					// 使用JSON发送消息
					msg := server.Message{
						Type:    "text",
						Content: "Server JSON broadcast message: " + time.Now().Format(time.RFC3339),
					}

					// 将消息转换为JSON
					msgBytes, err := json.Marshal(msg)
					if err != nil {
						log.Printf("Failed to marshal JSON broadcast message: %v", err)
						continue
					}

					// 发布消息到news主题
					wsServer.Publish("news", msgBytes)
					log.Println("JSON broadcast message sent to topic: news")
				}
			case <-stop:
				return
			}
		}
	}()

	// 等待中断信号
	<-stop
	log.Println("Shutting down server...")

	// 创建一个5秒的上下文用于优雅关闭
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	// 优雅关闭HTTP服务器
	if err := httpServer.Shutdown(ctx); err != nil {
		log.Fatalf("Server forced to shutdown: %v", err)
	}

	// 关闭长连接服务器
	if err := wsServer.Close(); err != nil {
		log.Printf("Error closing WebSocket server: %v", err)
	}

	log.Println("Server exiting")
}

// corsMiddleware 添加CORS头信息，允许跨域请求
func corsMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// 允许所有来源的请求
		w.Header().Set("Access-Control-Allow-Origin", "*")
		// 允许的请求方法
		w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
		// 允许的请求头
		w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
		// 允许浏览器缓存预检请求结果的时间（秒）
		w.Header().Set("Access-Control-Max-Age", "3600")

		// 处理预检请求
		if r.Method == "OPTIONS" {
			w.WriteHeader(http.StatusOK)
			return
		}

		// 继续处理请求
		next.ServeHTTP(w, r)
	})
}
